<?php
/**
 *+------------------
 * Lflow
 *+------------------
 * Copyright (c) 2023~2030 gitee.com/liu_guan_qing All rights reserved.本版权不可删除，侵权必究
 *+------------------
 * Author: Mr.April(405784684@qq.com)
 *+------------------
 */

namespace lflow\core\services;

use lflow\core\BaseServices;
use lflow\core\Execution;
use lflow\core\QueryServices;
use lflow\dao\OrderDao;
use lflow\lib\util\AssertHelper;
use lflow\lib\util\ClassUtil;
use lflow\lib\util\DateHelper;
use lflow\lib\util\Logger;
use lflow\lib\util\ObjectHelper;
use lflow\lib\util\StringHelper;
use lflow\model\OrderModel;
use lflow\model\ProcessModel;

class OrderServices extends BaseServices
{

    public function __construct(OrderDao $dao)
    {
        $this->dao = $dao;
    }

    /**
     * 创建活动实例
     *
     * @param \lflow\model\ProcessModel $process
     * @param string                    $operator
     * @param string|object             $args
     * @param string                    $parentId
     * @param string                    $parentNodeName
     * @param int                       $priority
     *
     * @return \lflow\model\OrderModel
     */
    public function createOrder(ProcessModel $process, string $operator, string|object $args, string $parentId = '', string $parentNodeName = '', int $priority = 1): OrderModel
    {
        $order = new OrderModel();//不能直接Dao 因为一次操作会创建多次
        $order->set('id', StringHelper::getPrimaryKey());
        $order->set('process_id', $process->getData('id'));
        $order->set('parent_id', $parentId ?? '');
        $order->set('parent_node_name', $parentNodeName ?? '');
        $order->set('creator', $operator);
        $order->set('create_time', DateHelper::getTime());
        $order->set('expire_time', '');
        $order->set('priority', $priority);
        $order->set('parent_id', $parentId);
        $processCkpt = $process->getData('process_ckpt');//；流程模型对象
        if ($processCkpt != null && $args != null) {
            if (StringHelper::isNotEmpty($processCkpt->getExpireTime())) {
//                $expireTime = DateHelper::parseTime());
                $expireTime = '';
                $order->set('expire_time', $expireTime ?? '');
            }
            $orderNo = $args->orderNo ?? '';
            if (StringHelper::isNotEmpty($orderNo)) {
                $order->set('order_no', $orderNo);
            } else {
                $order->set('order_no', $processCkpt->getGenerator()->generate($processCkpt));
            }
        }
        $order->set('variable', $args);
        $this->saveOrder($order);
        return $order;
    }

    public function saveOrder(OrderModel $order): void
    {
        $historyOrderServices = app()->make(HistoryOrderServices::class);
        $historyOrder         = $historyOrderServices->historyOrder($order);
        $historyOrder->set('order_state', self::STATE_ACTIVE);
        $order->save();
        $historyOrder->save();
    }

    /**
     * 完成实例
     *
     * @param string $orderId
     */
    public function complete(string $orderId, Execution $execution): void
    {
        AssertHelper::notNull($orderId ?? '', '[orderId] - this argument is required; it must not be null');
        $historyOrderServices = app()->make(HistoryOrderServices::class);
        $order                = $this->get($orderId);
        $historyOrder         = $historyOrderServices->get($orderId);
        $historyOrder->set('order_state', self::STATE_FINISH);
        $historyOrder->set('end_time', DateHelper:: getTime());
        $historyOrder->save();
        $order->delete();

        //任务完成事件
        $ckpt       = $execution->getProcess()->getData('process_ckpt');
        $completion = $ckpt->getCompletion();
        if ($completion != null) {
            $completion->complete($historyOrder);
        }
    }

    /**
     * 更新实例变量
     *
     * @param string       $orderId
     * @param array|object $args
     */
    public function addVariable(string $orderId, array|object $args)
    {
        AssertHelper::notNull($orderId);
        $order    = $this->get($orderId);
        $variable = $order->getData('variable');
        $args     = array_merge((array)$variable, (array)$args);//合并对象
        $order->set('variable', (object)$args);
        $order->save();
    }

    /**
     * 级联删除指定流程实例的所有数据：
     * 1.wf_order,wf_hist_order
     * 2.wf_task,wf_hist_task
     * 3.wf_task_actor,wf_hist_task_actor
     * 4.wf_cc_order
     *
     * @param string $orderId
     */
    public function cascadeRemove(string $orderId): void
    {
        $queryServices = app()->make(QueryServices::class);
        $historyOrder  = $queryServices->getHistOrder($orderId);
        AssertHelper:: notNull($historyOrder);
        $activeTasks  = $queryServices->getActiveTasks(['order_id' => $orderId]);
        $historyTasks = $queryServices->getHistoryTasks(['order_id' => $orderId]);
        foreach ($activeTasks['list'] as $task) {
            $task->delete();
        }
        foreach ($historyTasks['list'] as $historyTask) {
            $historyTask->delete();
        }

        $ccOrders = $queryServices->getCCOrder($orderId);
        foreach ($ccOrders as $ccOrder) {
            $ccOrder->delete();
        }
        $order = $queryServices->getOrder($orderId);
        $historyOrder->delete();
        if (!empty($order)) {
            $order->delete();
        }
    }
}
